package com.train.redis.config;

import cn.hutool.core.util.ReflectUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

/**
 * redis序列化配置
 */
@AutoConfiguration
@EnableCaching //开启缓存注解
public class RedisAutoConfig {

    /**
     * key和value的序列化配置
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        //客户端连接redis服务
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //序列化key为string
        redisTemplate.setKeySerializer(RedisSerializer.string());
        redisTemplate.setHashKeySerializer(RedisSerializer.string());
        //解决LocalDateTime和LocalDate序列化
        redisTemplate.setValueSerializer(redisSerializer());
        redisTemplate.setHashValueSerializer(redisSerializer());
        return redisTemplate;
    }

    public static RedisSerializer<Object> redisSerializer() {
        RedisSerializer<Object> json = RedisSerializer.json();
        // 解决 LocalDateTime 的序列化
        ObjectMapper objectMapper = (ObjectMapper) ReflectUtil.getFieldValue(json, "mapper");
        //设置时间模块(格式化，不设置，则输出默认格式)
        JavaTimeModule timeModule = new JavaTimeModule();
        // LocalDateTime
        DateTimeFormatter localDateTimeFormatter = getDateTimeFormatter("yyyy-MM-dd HH:mm:ss", "Asia/Shanghai");
        DateTimeFormatter localDateFormatter = getDateTimeFormatter("yyyy-MM-dd", "Asia/Shanghai");
        timeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(localDateTimeFormatter));
        timeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(localDateTimeFormatter));
        // LocalDate
        timeModule.addSerializer(LocalDate.class, new LocalDateSerializer(localDateFormatter));
        timeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(localDateFormatter));
        // 设置自定义时间模块
        objectMapper.registerModule(timeModule);
        return new GenericJackson2JsonRedisSerializer(objectMapper);
    }

    public static DateTimeFormatter getDateTimeFormatter(String format, String zone) {
        return DateTimeFormatter.ofPattern(format).withZone(ZoneId.of(zone));
    }
}
